package com.shm.singlecamera.Utils;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class CameraRender implements GLSurfaceView.Renderer {

    private final float[] mvpMatrix = new float[16];
    private final float[] projectionMatrix = new float[16];
    private final float[] viewMatrix = new float[16];

    private FloatBuffer vertexBuffer;
    private FloatBuffer textureBuffer;

    private int textureId = -1;
    private int programId;

    private int mvpMatrixHandle;
    private int positionHandle;
    private int textureCoordHandle;
    private int textureHandle;

    private ByteBuffer pixelBuffer;
    private int imageWidth = 0;
    private int imageHeight = 0;

    // 顶点坐标（全屏四边形）
    private final float[] vertexCoords = {
            -1.0f, -1.0f,  // 左下
            1.0f, -1.0f,   // 右下
            -1.0f, 1.0f,   // 左上
            1.0f, 1.0f     // 右上
    };

    // 纹理坐标（根据Mat方向调整）
    private final float[] textureCoords = {
            0.0f, 1.0f,    // 左下
            1.0f, 1.0f,    // 右下
            0.0f, 0.0f,    // 左上
            1.0f, 0.0f     // 右上
    };

    // 顶点着色器代码
    private final String vertexShaderCode =
            "attribute vec4 vPosition;\n" +
                    "attribute vec2 vTexCoord;\n" +
                    "varying vec2 texCoord;\n" +
                    "uniform mat4 uMVPMatrix;\n" +
                    "void main() {\n" +
                    "  gl_Position = uMVPMatrix * vPosition;\n" +
                    "  texCoord = vTexCoord;\n" +
                    "}";

    // 片段着色器代码
    // 片段着色器代码
    private final String fragmentShaderCode =
          "precision mediump float;\n" + // 注意换行符
          "varying vec2 texCoord;\n" +  // 接收顶点着色器传递的纹理坐标
          "uniform sampler2D tex;\n" + // 纹理采样器 uniform 变量，与 Java 代码中的 textureHandle 对应
          "void main() {\n" +
          "  gl_FragColor = texture2D(tex, texCoord);\n" + // 使用 texture2D 函数采样纹理颜色
          "}";

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 初始化OpenGL状态
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        GLES20.glEnable(GLES20.GL_TEXTURE_2D);

        // 初始化顶点和纹理坐标缓冲区
        ByteBuffer bb = ByteBuffer.allocateDirect(vertexCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(vertexCoords);
        vertexBuffer.position(0);

        ByteBuffer tb = ByteBuffer.allocateDirect(textureCoords.length * 4);
        tb.order(ByteOrder.nativeOrder());
        textureBuffer = tb.asFloatBuffer();
        textureBuffer.put(textureCoords);
        textureBuffer.position(0);

        // 创建纹理
        int[] textures = new int[1];
        GLES20.glGenTextures(1, textures, 0);
        textureId = textures[0];
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

        // 编译着色器
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

        programId = GLES20.glCreateProgram();
        GLES20.glAttachShader(programId, vertexShader);
        GLES20.glAttachShader(programId, fragmentShader);
        GLES20.glLinkProgram(programId);

        // 获取属性/统一变量位置
        positionHandle = GLES20.glGetAttribLocation(programId, "vPosition");
        textureCoordHandle = GLES20.glGetAttribLocation(programId, "vTexCoord");
        mvpMatrixHandle = GLES20.glGetUniformLocation(programId, "uMVPMatrix");
        textureHandle = GLES20.glGetUniformLocation(programId, "tex");
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);

        // 设置正交投影矩阵
        Matrix.setIdentityM(projectionMatrix, 0);
        Matrix.orthoM(projectionMatrix, 0, -1, 1, -1, 1, -1, 1);

        Matrix.setIdentityM(viewMatrix, 0);
        Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        synchronized (this) {

            if (pixelBuffer != null) {
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
                // 设置解包对齐为1字节，避免宽度非4倍数的问题
                GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
                GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB,
                        imageWidth, imageHeight, 0, GLES20.GL_RGB,
                        GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
                pixelBuffer = null;
            }
        }

        GLES20.glUseProgram(programId);

        GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0);

        GLES20.glEnableVertexAttribArray(positionHandle);
        GLES20.glVertexAttribPointer(positionHandle, 2,
                GLES20.GL_FLOAT, false, 0, vertexBuffer);

        GLES20.glEnableVertexAttribArray(textureCoordHandle);
        GLES20.glVertexAttribPointer(textureCoordHandle, 2,
                GLES20.GL_FLOAT, false, 0, textureBuffer);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        GLES20.glUniform1i(textureHandle, 0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        GLES20.glDisableVertexAttribArray(positionHandle);
        GLES20.glDisableVertexAttribArray(textureCoordHandle);

    }

    // 从JNI调用此方法更新纹理数据
    public synchronized void updateFrame(byte[] data, int width, int height) {
        imageWidth = width;
        imageHeight = height;
        pixelBuffer = ByteBuffer.allocateDirect(data.length);
        pixelBuffer.put(data);
        pixelBuffer.position(0);
    }

    private int loadShader(int type, String shaderCode) {
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }

}